package cn.iocoder.yudao.module.pay.service.premium;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
import cn.iocoder.yudao.module.trade.api.record.BrokerageRecordApi;
import cn.iocoder.yudao.module.trade.api.record.dto.BrokerRecordDTO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.wine.api.*;
import cn.iocoder.yudao.module.wine.api.dto.*;
import cn.iocoder.yudao.module.wine.enums.MemberTermEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;

/**
 * @author zyc
 * @createDate 2024/5/14 10:25
 */
@Service
@Validated
@Slf4j
public class PayPremiumServiceImpl implements PayPremiumService {

    //region 代码块

    @Resource
    private PremiumApi premiumApi;

    @Resource
    private SupplyOrderApi supplyOrderApi;

    @Resource
    private PayChannelService channelService;

    @Resource
    private PayAppService appService;

    @Resource
    private PayNoRedisDAO noRedisDAO;

    @Resource
    private PayProperties payProperties;

    @Resource
    private MemberDeadlineApi memberDeadlineApi;

    @Resource
    private GuaranteeRecordApi guaranteeRecordApi;

    @Resource
    private TeamTypeApi teamTypeApi;

    @Resource
    private BrokerageRecordApi brokerageRecordApi;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private WineConfigApi wineConfigApi;

    @Resource
    private  BusinessUserApi businessUserApi;
    //endregion


    @Override
    public PayClient getPayClient(Long channelId) {
        return channelService.getPayClient(channelId);
    }

    /**
     * 根据订单ID获取保费信息
     * @param orderId
     * @return
     */
    @Override
    public PremiumRecordDTO getPremiumRecord(Long orderId) {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        SupplyOrderDTO orderById = supplyOrderApi.getOrderById(orderId);
        Long buyUserId = orderById.getBuyUserId();
        Long saleUserId = orderById.getSaleUserId();
        if (!saleUserId.equals(loginUserId) && !buyUserId.equals(loginUserId)) throw exception(PAY_SYSTEM_ERROR);
        return premiumApi.getPremiumByOrder(loginUserId, orderId);
    }

    /**
     * 支付保费
     *
     * @param reqVO
     * @return
     */
    @Override
    public PayOrderSubmitRespVO payPremium(PayOrderSubmitReqVO reqVO) {
        // 1. 校验支付渠道是否有效
        String code = PayChannelEnum.WX_LITE.getCode();
        PayChannelDO channel = validateChannelCanSubmit(1L, code);
        PayClient client = channelService.getPayClient(channel.getId());
        // 3. 调用三方接口
        String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
        PremiumRecordDTO premiumRecordDTO = premiumApi.getPremiumById(reqVO.getId());
        PayOrderUnifiedReqDTO unifiedOrderReqDTO = new PayOrderUnifiedReqDTO();
        // 商户相关的字段
        unifiedOrderReqDTO
                .setOutTradeNo(no) // 注意，此处使用的是 PayOrderExtensionDO.no 属性！
                .setSubject(no + "-保费")
                .setBody("支付担保费")
                .setNotifyUrl(genChannelPremiumNotifyUrl(channel))
                .setReturnUrl(reqVO.getReturnUrl()).setUserIp(getClientIP()).setChannelExtras(reqVO.getChannelExtras())
                // 订单相关字段
                .setPrice(premiumRecordDTO.getPremium().multiply(new BigDecimal(100)).intValue())
                .setExpireTime(LocalDateTime.now().plusHours(2L));

        PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);

        // 4. 如果调用直接支付成功，则直接更新支付单状态为成功。例如说：付款码支付，免密支付时，就直接验证支付成功
        PayOrderSubmitRespVO payOrderSubmitRespVO = new PayOrderSubmitRespVO();
        if (unifiedOrderResp != null) {
            getSelf().notifyPremium(channel, unifiedOrderResp);
            // 如有渠道错误码，则抛出业务异常，提示用户
            if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
                        unifiedOrderResp.getChannelErrorMsg());
            }
            premiumRecordDTO.setTradeNo(no);
            log.info("支付的保费信息: {}", premiumRecordDTO);
            premiumApi.updateTradeNo(premiumRecordDTO);

            payOrderSubmitRespVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
            payOrderSubmitRespVO.setDisplayMode(unifiedOrderResp.getDisplayMode());
            payOrderSubmitRespVO.setDisplayContent(unifiedOrderResp.getDisplayContent());
        }
        return payOrderSubmitRespVO;

    }

    /**
     * 团长缴费
     *
     * @param reqVO
     * @return
     */
    @Override
    public PayOrderSubmitRespVO payTeamFees(PayOrderSubmitReqVO reqVO) {
        Long teamId = reqVO.getId();
        TeamTypeDTO teamTypeInfo = teamTypeApi.getTeamTypeInfo(teamId);
        String code = PayChannelEnum.WX_LITE.getCode();
        PayChannelDO channel = validateChannelCanSubmit(1L, code);
        PayClient client = channelService.getPayClient(channel.getId());
        // 3. 调用三方接口
        String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
        PayOrderUnifiedReqDTO unifiedOrderReqDTO = new PayOrderUnifiedReqDTO();
        // 商户相关的字段
        unifiedOrderReqDTO
                .setOutTradeNo(no) // 注意，此处使用的是 PayOrderExtensionDO.no 属性！
                .setSubject(no + "-团长费用")
                .setBody("开通团长缴费")
                .setNotifyUrl(genChannelGuaranteeNotifyUrl(channel))
                .setReturnUrl(reqVO.getReturnUrl())
                .setUserIp(getClientIP())
                .setChannelExtras(reqVO.getChannelExtras())
                // 订单相关字段
                .setPrice(teamTypeInfo.getPrice().multiply(new BigDecimal(100)).intValue())
                .setExpireTime(LocalDateTime.now().plusHours(2L));

        PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
        // 4. 如果调用直接支付成功，则直接更新支付单状态为成功。例如说：付款码支付，免密支付时，就直接验证支付成功
        PayOrderSubmitRespVO payOrderSubmitRespVO = new PayOrderSubmitRespVO();
        if (unifiedOrderResp != null) {
            getSelf().notifyOrder(channel, unifiedOrderResp);
            // 如有渠道错误码，则抛出业务异常，提示用户
            if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
                        unifiedOrderResp.getChannelErrorMsg());
            }
            payOrderSubmitRespVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
            payOrderSubmitRespVO.setDisplayMode(unifiedOrderResp.getDisplayMode());
            payOrderSubmitRespVO.setDisplayContent(unifiedOrderResp.getDisplayContent());
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();

            // 记录开通缴费日志
            GuaranteeRecordDTO guaranteeRecordDTO = new GuaranteeRecordDTO();
            guaranteeRecordDTO.setUserId(loginUserId);
            guaranteeRecordDTO.setTradeNo(no);
            guaranteeRecordDTO.setGuaranteePrice(teamTypeInfo.getPrice());
            guaranteeRecordDTO.setTeamTypeId(teamId);
            guaranteeRecordDTO.setRemark("用户id为" + loginUserId + "缴纳了团长费用");
            guaranteeRecordApi.addGuaranteeRecord(guaranteeRecordDTO);
        }
        return payOrderSubmitRespVO;
    }

    /**
     * 开通会员
     *
     * @param reqVO
     * @return
     */
    @Override
    public PayOrderSubmitRespVO payMembershipFees(PayOrderSubmitReqVO reqVO) {
        Long memberTypeId = reqVO.getId();
        MemberTypeDTO memberTypeInfo = memberDeadlineApi.getMemberTypeInfo(memberTypeId);

        String code = PayChannelEnum.WX_LITE.getCode();
        PayChannelDO channel = validateChannelCanSubmit(1L, code);
        PayClient client = channelService.getPayClient(channel.getId());
        // 3. 调用三方接口
        String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
        PayOrderUnifiedReqDTO unifiedOrderReqDTO = new PayOrderUnifiedReqDTO();
        // 商户相关的字段
        unifiedOrderReqDTO
                .setOutTradeNo(no) // 注意，此处使用的是 PayOrderExtensionDO.no 属性！
                .setSubject(no + "-会员费用")
                .setBody("开通会员费用")
                .setNotifyUrl(genChannelMemberNotifyUrl(channel))
                .setReturnUrl(reqVO.getReturnUrl()).setUserIp(getClientIP()).setChannelExtras(reqVO.getChannelExtras())
                // 订单相关字段
                .setPrice(memberTypeInfo.getPrice().multiply(new BigDecimal(100)).intValue())
                .setExpireTime(LocalDateTime.now().plusHours(2L));

        PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
        // 4. 如果调用直接支付成功，则直接更新支付单状态为成功。例如说：付款码支付，免密支付时，就直接验证支付成功
        PayOrderSubmitRespVO payOrderSubmitRespVO = new PayOrderSubmitRespVO();
        if (unifiedOrderResp != null) {
            getSelf().notifyOrder(channel, unifiedOrderResp);
            // 如有渠道错误码，则抛出业务异常，提示用户
            if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
                        unifiedOrderResp.getChannelErrorMsg());
            }
            payOrderSubmitRespVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
            payOrderSubmitRespVO.setDisplayMode(unifiedOrderResp.getDisplayMode());
            payOrderSubmitRespVO.setDisplayContent(unifiedOrderResp.getDisplayContent());
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();

            // 记录开通会员日志
            MemberOpenLogDTO memberOpenLogDTO = new MemberOpenLogDTO();
            memberOpenLogDTO.setUserId(loginUserId);
            memberOpenLogDTO.setPrice(memberTypeInfo.getPrice().multiply(new BigDecimal(100)).intValue());
            memberOpenLogDTO.setMemberTypeId(memberTypeId);
            memberOpenLogDTO.setTradeNo(no);
            memberOpenLogDTO.setRemark("用户id为" + loginUserId + "开通了VIP认证会员");
            memberDeadlineApi.addMemberOpenLog(memberOpenLogDTO);
        }
        return payOrderSubmitRespVO;
    }

    /**
     * 开通会员-通知
     *
     * @param channelId 渠道编号
     * @param notify    通知
     */
    @Override
    public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
        // 校验支付渠道是否有效
        PayChannelDO channel = channelService.validPayChannel(channelId);
        Long tenantId = channel.getTenantId();

        //如果有收益年数，则计算有效期限
        Integer profitYear = 0;
        WineConfigDTO wineConfigDTO = wineConfigApi.getWineConfigInfo();
        if (wineConfigDTO != null && wineConfigDTO.getIsOpenMonth() > 0 && wineConfigDTO.getFreeMonth() > 0) {
            profitYear = wineConfigDTO.getProfitYear();
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endTime = now.plusYears(profitYear);

        String outTradeNo = notify.getOutTradeNo();
        MemberOpenLogDTO memberOpenLogDTO = memberDeadlineApi.getMemberOpenLog(outTradeNo);

        Long memberTypeId = memberOpenLogDTO.getMemberTypeId();
        Long loginUserId = memberOpenLogDTO.getUserId();
        Long bindUserId = 0L;

        MemberTypeDTO memberTypeInfo = memberDeadlineApi.getMemberTypeInfo(memberTypeId);
        Integer termType = memberTypeInfo.getTermType();

        //当前用户的上级用户id
        log.info("当前用户的id:{}", loginUserId);
        BrokerageUserNewDTO brokerageUserDTO = memberDeadlineApi.getBrokerageUser(loginUserId);
        if (brokerageUserDTO != null) {
            bindUserId = brokerageUserDTO.getBindUserId();
            //没认证的设为认证
            if (brokerageUserDTO.getBusinessType() == 0) {
                brokerageUserDTO.setBrokerageEnabled(true);
                brokerageUserDTO.setBusinessType(1);
                brokerageUserDTO.setUserBusiness(1);
                brokerageUserDTO.setBusinesStartTime(now);
                brokerageUserDTO.setBusinessEndTime(endTime);
                memberDeadlineApi.updateBrokerageUser(brokerageUserDTO);
            }
        } else {
            //添加默认，防止出错
            BrokerageUserNewDTO brokerageUser = new BrokerageUserNewDTO();
            brokerageUser.setId(loginUserId);
            brokerageUser.setBrokerageEnabled(false);
            brokerageUser.setBindUserId(0L);
            brokerageUser.setBusinessType(1);
            brokerageUser.setUserBusiness(0);
            brokerageUser.setBusinesStartTime(now);
            brokerageUser.setBusinessEndTime(endTime);
            //通知返回操作没有登录信息，所以不能自动填充租户ID，因此租户ID要手动赋值。
            brokerageUser.setTenantId(tenantId);
            memberDeadlineApi.addBrokerageUser(brokerageUser);
        }

        log.info("用户的上级id:{}", bindUserId);

        MemberDeadlineDTO memberDeadline = memberDeadlineApi.getMemberDeadlineByUserId(loginUserId);
        log.info("会员的期限信息:{}", memberDeadline);

        //更新商家表的信息
        BusinessUserDTO businessUser = businessUserApi.getBusinessUserByUserId(loginUserId);

        //原来的结束时间
        LocalDate oldEndNow = LocalDate.now();
        //开始时间与结束时间
        LocalDate endNow = LocalDate.now();
        //没有开通记录
        if (memberDeadline == null) {

            businessUser.setAuthTime(now);
            businessUser.setOpenTime(now);

            //region 没有记录
            LocalDate startNow = LocalDate.now();
            MemberDeadlineDTO data = new MemberDeadlineDTO();
            data.setMemberTypeId(memberTypeId);
            data.setUserId(loginUserId);
            data.setStartDate(startNow);
            //根据类型计算时间
            if (MemberTermEnum.MONTH.getCode().equals(termType)) {
                endNow = startNow.plusMonths(1L);
            }
            if (MemberTermEnum.QUARTER.getCode().equals(termType)) {
                endNow = startNow.plusMonths(3L);
            }
            if (MemberTermEnum.HALF_A_YEAR.getCode().equals(termType)) {
                endNow = startNow.plusMonths(6L);
            }
            if (MemberTermEnum.YEAR.getCode().equals(termType)) {
                endNow = startNow.plusYears(1L);
            }
            data.setEndDate(endNow);
            memberDeadlineApi.addMemberDeadline(data);
            //endregion

        } else {

            memberDeadline.setMemberTypeId(memberTypeId);
            //过期了按补齐规则处理：09.20确认

            //region 已有记录
            oldEndNow = memberDeadline.getEndDate();
            if (MemberTermEnum.MONTH.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(1L);
            }
            if (MemberTermEnum.QUARTER.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(3L);
            }
            if (MemberTermEnum.HALF_A_YEAR.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(6L);
            }
            if (MemberTermEnum.YEAR.getCode().equals(termType)) {
                endNow = oldEndNow.plusYears(1L);
            }
            memberDeadline.setEndDate(endNow);
            memberDeadlineApi.editMemberDeadline(memberDeadline);
            //endregion
        }
        //增加当前开通这条记录的开始时间和结束时间
        memberOpenLogDTO.setType(1);
        memberOpenLogDTO.setStartDate(oldEndNow);
        memberOpenLogDTO.setEndDate(endNow);
        // 更新支付订单为已支付
        memberOpenLogDTO.setStatus(1);
        memberDeadlineApi.editMemberOpenLog(memberOpenLogDTO);

        //更新商家表信息，只要付款了就认证开通了
        businessUser.setIsAuth(1);
        //入驻商家--1,认证商家--2,商家团长--3,个人团长--4，保证金用户--5
        businessUser.setCreditId(2);//VIP认证角色
        businessUser.setOverTime(endNow.atStartOfDay());
        businessUserApi.updateBusinessUserInfo(businessUser);

        if (bindUserId > 0) {

            //当前开通的用户是否是还是所属下级规则：后台开关>有效期
            int isTeamChild = 1;
            int isCanSettable = 1;

            //1.绑定上级推广员的佣金信息，如果被后台关闭，（产生佣金记录，但不给期结算佣金）
            Boolean brokerageEnabled = true;
            Integer isTeamType = 0;
            BrokerageUserNewDTO parBrokerageUser = memberDeadlineApi.getBrokerageUser(bindUserId);
            if (parBrokerageUser != null) {
                brokerageEnabled = parBrokerageUser.getBrokerageEnabled();
                isTeamType = parBrokerageUser.getTeamType();
            }

            //1.获取上级用户信息
            MemberUserRespDTO bindUser = memberUserApi.getUser(bindUserId);
            //查询上级如果是个人团长，并且是后台加的，将是不限期，按开关处理
            if (bindUser.getIsBusiness() == 2 &&
                    bindUser.getIsTeam() == 1 &&
                    Objects.equals(bindUser.getRegisterTerminal(), TerminalEnum.ADMIN_INSERT.getTerminal()))
            {
                if (!brokerageEnabled) {
                    isCanSettable = 0;//不可结算
                }
                //不限期，所以都是属于上级
            }
            else {
                //1.当前用户的上级，他的团长的过期时间
                LocalDateTime parentTeamOpenTime = bindUser.getTeamOpenTime();
                LocalDateTime parentTeamOverTime = bindUser.getTeamOverTime();
                //当前用户的上级的，他开通的有效结束时间，在当前时间之后，则当前用户属于当他的有效下级
                //现在时间 在免费时间之后，说明到期了
                if (now.isAfter(endTime)) {
                    //免费到期后判断是否过期
                    if (parentTeamOverTime != null) {
                        if (parentTeamOpenTime.isAfter(now) || parentTeamOverTime.isBefore(now)) {
                            isTeamChild = 0;
                        }
                    }
                }
                //如果当前用户第一次开通认证，则检测用户的注册时间
                if (memberDeadline == null && isTeamChild == 1) {
                    MemberUserRespDTO loginUser = memberUserApi.getUser(loginUserId);
                    LocalDateTime regTime = loginUser.getCreateTime();
                    //当前用户的注册时间在上级的开通时间之前，说明上级续费后间断一定时间后 再续费
                    if (parentTeamOpenTime != null && regTime.isBefore(parentTeamOpenTime)) {
                        isTeamChild = 0;
                    }
                }

                //上级没有开启、上级没有认证、不是该用户的有效上级  则不可结算
                if (!brokerageEnabled) {
                    isCanSettable = 0;//不可结算
                }
                else if (isTeamType == 0) {
                    isCanSettable = 0;//不可结算
                }
                else if (isTeamChild == 0) {
                    isCanSettable = 0;//不可结算
                }
            }

            //获取当前用户分销记录信息
            BrokerageUserNewDTO brokerageUser = memberDeadlineApi.getBrokerageUserByIds(bindUserId, loginUserId);
            if (brokerageUser != null) {
                Integer oldUserTeam = brokerageUser.getUserTeam();
                if (oldUserTeam == null) {
                    oldUserTeam = 0;
                    brokerageUser.setUserTeam(isTeamChild);
                }
                //都还是属于上级，并且时间不一样,上级不能断掉续费
                if (!oldUserTeam.equals(isTeamChild)) {
                    brokerageUser.setUserTeam(isTeamChild);
                }
                memberDeadlineApi.updateBrokerageUser(brokerageUser);
            }

            //判断该推广员是个人团长还是商家团长，个人团长使用个人团长的佣金比例，商家团长使用商家的比例配置计算佣金
            BigDecimal commissionRate = BigDecimal.valueOf(0L);
            if (bindUser.getIsBusiness() == 1 && bindUser.getIsTeam() == 1) {
                commissionRate = memberTypeInfo.getBussCommissionRate(); //商家团长比例
            } else if (bindUser.getIsBusiness() == 2 && bindUser.getIsTeam() == 1) {
                commissionRate = memberTypeInfo.getTeamCommissionRate(); //个人团长比例
            }
            //2.有佣金的时候才插入记录(不管是否可结算都插入，方便核对数据)
            if (commissionRate.compareTo(BigDecimal.ZERO) > 0) {
                String errMsg = "";
                //是否所属团长的子级(做标记)
                if (isTeamChild == 0) {
                    errMsg = "过期";
                }
                if (isTeamChild == 1) {
                    errMsg = "有效";
                }
                //该拥挤的结算状态
                Integer settlementStatus = BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus();
                if (isCanSettable == 0) {
                    settlementStatus = BrokerageRecordStatusEnum.CANCEL.getStatus(); //取消
                }

                BigDecimal divide = new BigDecimal(String.valueOf(commissionRate)).divide(new BigDecimal(100), 3, RoundingMode.HALF_UP);
                BigDecimal priceMultiply = memberTypeInfo.getPrice().multiply(divide);
                Integer totalAmount = memberTypeInfo.getPrice().multiply(new BigDecimal(100)).intValue();

                String desc = "VIP升级的返佣金额:" + priceMultiply + "元(" + errMsg + ")";

                //  需要记录每一笔佣金产生日志  待完成
                BrokerRecordDTO brokerRecordDTO = new BrokerRecordDTO();

                brokerRecordDTO.setUserId(bindUserId);
                brokerRecordDTO.setBizId(outTradeNo);
                brokerRecordDTO.setBizType(BrokerageRecordBizTypeEnum.VIP.getType());
                brokerRecordDTO.setPrice(priceMultiply.multiply(new BigDecimal(100)).intValue());
                brokerRecordDTO.setTotalPrice(0);
                brokerRecordDTO.setTotalAmount(totalAmount);
                brokerRecordDTO.setTitle("VIP升级返佣");
                brokerRecordDTO.setDescription(desc);
                brokerRecordDTO.setStatus(settlementStatus);
                brokerRecordDTO.setFrozenDays(0);
                brokerRecordDTO.setSourceUserLevel(0);
                brokerRecordDTO.setSourceUserId(loginUserId);
                //判断当前上级用户是否过期，过期的佣金不给与结算
                brokerRecordDTO.setCanSettable(isCanSettable);
                //通知返回操作没有登录信息，所以不能自动填充租户ID，因此租户ID要手动赋值。
                brokerRecordDTO.setTenantId(tenantId);

                log.info("VIP认证佣金记录:{}", brokerRecordDTO);
                brokerageRecordApi.insertRecord(brokerRecordDTO);
                //更新上级佣金账户，后台按条数进行结算，因此不要处理用户的佣金账户
                //......
            }
        }
    }

    /**
     * 团长缴费-通知
     *
     * @param channelId
     * @param notify
     */
    @Override
    public void notifyGuarantee(Long channelId, PayOrderRespDTO notify) {
        // 校验支付渠道是否有效
        PayChannelDO channel = channelService.validPayChannel(channelId);
        Long tenantId = channel.getTenantId();

        //如果有收益年数，则计算有效期限
        Integer profitYear = 0;
        WineConfigDTO wineConfigDTO = wineConfigApi.getWineConfigInfo();
        if (wineConfigDTO != null && wineConfigDTO.getIsOpenMonth() > 0 && wineConfigDTO.getFreeMonth() > 0) {
            profitYear = wineConfigDTO.getProfitYear();
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endTime = now.plusYears(profitYear);

        String outTradeNo = notify.getOutTradeNo();
        GuaranteeRecordDTO guaranteeRecordByNo = teamTypeApi.getGuaranteeRecordByNo(outTradeNo);

        Long teamTypeId = guaranteeRecordByNo.getTeamTypeId();
        TeamTypeDTO teamTypeInfo = teamTypeApi.getTeamTypeInfo(teamTypeId);

        //查询当前用户团长缴费日期信息
        Long loginUserId = guaranteeRecordByNo.getUserId();
        MemberUserRespDTO loginUser = memberUserApi.getUser(loginUserId);

        Long bindUserId = 0L;
        //当前用户的上级用户id
        log.info("当前用户的id:{}", loginUserId);
        BrokerageUserNewDTO brokerageUserDTO = memberDeadlineApi.getBrokerageUser(loginUserId);
        if (brokerageUserDTO != null) {
            bindUserId = brokerageUserDTO.getBindUserId();
            //没认证的设为认证
            if (brokerageUserDTO.getTeamType() == 0) {
                brokerageUserDTO.setTeamType(1);
                brokerageUserDTO.setUserTeam(1);
                brokerageUserDTO.setTeamStartTime(now);
                brokerageUserDTO.setTeamEndTime(endTime);
                memberDeadlineApi.updateBrokerageUser(brokerageUserDTO);
            }
        } else {
            BrokerageUserNewDTO brokerageUser = new BrokerageUserNewDTO();
            brokerageUser.setId(loginUserId);
            brokerageUser.setBindUserId(0L);

            brokerageUser.setTeamType(1);
            brokerageUser.setUserTeam(0);
            brokerageUser.setTeamStartTime(now);
            brokerageUser.setTeamEndTime(endTime);
            memberDeadlineApi.addBrokerageUser(brokerageUser);
        }

        log.info("用户的上级id:{}", bindUserId);

        // 09.16 修改成 交团费无佣金，只有VIP认证才给上级佣金 - 删除代码
        Integer termType = teamTypeInfo.getTermType();

        if (bindUserId > 0) {
            //当前开通的用户是否是还是所属下级规则：后台开关>有效期
            int isTeamChild = 0;

            //上级用户信息
            MemberUserRespDTO bindUser = memberUserApi.getUser(bindUserId);
            if (bindUser.getIsBusiness() == 2 &&
                    bindUser.getIsTeam() == 1 &&
                    Objects.equals(bindUser.getRegisterTerminal(), TerminalEnum.ADMIN_INSERT.getTerminal())) {
                //不限期，所以都是属于上级
                isTeamChild = 1;
            } else {
                //2.上级团长的过期时间
                LocalDateTime parentTeamOpenTime = bindUser.getTeamOpenTime();
                LocalDateTime parentTeamOverTime = bindUser.getTeamOverTime();
                //当前用户的上级的，他开通的有效结束时间，在当前时间之后，则当前用户属于当他的有效下级
                if (parentTeamOverTime != null) {
                    if (parentTeamOverTime.isAfter(now) && endTime.isAfter(now)) {
                        isTeamChild = 1;
                    }
                    if (parentTeamOpenTime.isAfter(now)) {
                        isTeamChild = 0;
                    }
                    //如果当前用户第一次开通认证，则检测用户的注册时间
                    if (loginUser.getTeamOpenTime() == null && isTeamChild == 1) {
                        LocalDateTime regTime = loginUser.getCreateTime();
                        //当前用户的注册时间在上级的开通时间之前，说明上级续费后间断一定时间后 再续费
                        if (regTime.isBefore(parentTeamOpenTime)) {
                            isTeamChild = 0;
                        }
                    }
                }
            }

            //获取当前分销用户信息
            BrokerageUserNewDTO brokerageUser = memberDeadlineApi.getBrokerageUserByIds(bindUserId, loginUserId);
            if (brokerageUser != null) {
                //佣金账户
                Integer oldUserTeam = brokerageUser.getUserTeam();
                if (oldUserTeam == null) {
                    oldUserTeam = 0;
                    brokerageUser.setUserTeam(isTeamChild);
                }
                //都还是上级，并且时间不一样,上级不能断掉续费
                if (!oldUserTeam.equals(isTeamChild)) {
                    brokerageUser.setUserTeam(isTeamChild);
                }
                memberDeadlineApi.updateBrokerageUser(brokerageUser);
            }
        }

        LocalDateTime oldEndNow = LocalDateTime.now();
        LocalDateTime endNow = LocalDateTime.now();

        if (loginUser.getTeamOverTime() == null && loginUser.getTeamOpenTime() == null) {

            LocalDateTime startNow = LocalDateTime.now();
            loginUser.setTeamOpenTime(startNow);
            //根据类型计算时间
            if (MemberTermEnum.MONTH.getCode().equals(termType)) {
                endNow = startNow.plusMonths(1L);
            }
            if (MemberTermEnum.QUARTER.getCode().equals(termType)) {
                endNow = startNow.plusMonths(3L);
            }
            if (MemberTermEnum.HALF_A_YEAR.getCode().equals(termType)) {
                endNow = startNow.plusMonths(6L);
            }
            if (MemberTermEnum.YEAR.getCode().equals(termType)) {
                endNow = startNow.plusYears(1L);
            }
            loginUser.setTeamOverTime(endNow);
            memberUserApi.updateUserDateTime(loginUser);

        } else {

            oldEndNow = loginUser.getTeamOverTime();
            //过期了按补齐规则处理：09.20确认
            if (MemberTermEnum.MONTH.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(1L);
            }
            if (MemberTermEnum.QUARTER.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(3L);
            }
            if (MemberTermEnum.HALF_A_YEAR.getCode().equals(termType)) {
                endNow = oldEndNow.plusMonths(6L);
            }
            if (MemberTermEnum.YEAR.getCode().equals(termType)) {
                endNow = oldEndNow.plusYears(1L);
            }
            loginUser.setTeamOverTime(endNow);
            memberUserApi.updateUserDateTime(loginUser);
        }
        //增加当前开通这条记录的开始时间和结束时间
        guaranteeRecordByNo.setTradeTime(LocalDateTime.now());
        guaranteeRecordByNo.setStartTime(oldEndNow);
        guaranteeRecordByNo.setEndTime(endNow);
        // 更新支付订单为已支付
        guaranteeRecordByNo.setStatus(1);

        guaranteeRecordApi.editguaranteeRecord(guaranteeRecordByNo);

        //更新商家表的信息
        BusinessUserDTO businessUser = businessUserApi.getBusinessUserByUserId(loginUserId);
        if (businessUser != null && businessUser.getCreditId() == 2) {
            //必须先是认证商家--2 才能更新为商家团长--3

            //入驻商家--1,认证商家--2,商家团长--3,个人团长--4，保证金用户--5
            businessUser.setCreditId(3);//商家团长
            businessUserApi.updateBusinessUserInfo(businessUser);
        }
    }

    /**
     * 支付保费-通知
     *
     * @param channelId
     * @param notify
     */
    @Override
    public void notifyPremium(Long channelId, PayOrderRespDTO notify) {
        // 校验支付渠道是否有效
        PayChannelDO channel = channelService.validPayChannel(channelId);
        //判断支付成功则更新
        log.info("支付保费通知信息: {}", notify);
        //应该要判断状态成功才能更新？
        //if(Objects.equals(notify.getStatus(), PayOrderStatusRespEnum.SUCCESS.getStatus())){
            Long curTenantId = channel.getTenantId();
        //}
        // 更新支付订单为已支付
        premiumApi.updateStatus(notify.getOutTradeNo(),curTenantId);
    }

    /**
     * 保费支付成功回调
     * @param channel
     * @param notify
     */
    @Transactional(rollbackFor = Exception.class)
    // 注意，如果是方法内调用该方法，需要通过 getSelf().notifyPayOrder(channel, notify) 调用，否则事务不生效
    public void notifyPremium(PayChannelDO channel, PayOrderRespDTO notify) {
        // 情况一：支付成功的回调
        if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
            notifyPremiumSuccess(channel, notify);
            return;
        }
        if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
            throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, notify.getChannelErrorCode(), notify.getChannelErrorMsg());
        }
        // 情况二：支付失败的回调

        // 情况三：WAITING：无需处理

        // 情况四：REFUND：通过退款回调处理
    }

    /**
     * 情况一：支付成功的回调
     * @param channel
     * @param notify
     */
    private void notifyPremiumSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
        // 1. 更新 PremiumRecordDO 支付成功
    }

    /**
     * 订单支付成功回调
     * @param channel
     * @param notify
     */
    @Transactional(rollbackFor = Exception.class)
    // 注意，如果是方法内调用该方法，需要通过 getSelf().notifyPayOrder(channel, notify) 调用，否则事务不生效
    public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
        // 情况一：支付成功的回调
        if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
            notifyOrderSuccess(channel, notify);
            return;
        }
        if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
            throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, notify.getChannelErrorCode(), notify.getChannelErrorMsg());
        }
        // 情况二：支付失败的回调

        // 情况三：WAITING：无需处理

        // 情况四：REFUND：通过退款回调处理
    }

    /**
     * 情况一：支付成功的回调
     * @param channel
     * @param notify
     */
    private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
        // 1. 更新 PayOrderExtensionDO 支付成功
        // 3. 插入支付通知记录
    }



    private PayPremiumServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

    private String genChannelPremiumNotifyUrl(PayChannelDO channel) {
        return payProperties.getPremiumNotifyUrl() + "/" + channel.getId();
    }

    private String genChannelGuaranteeNotifyUrl(PayChannelDO channel) {
        return payProperties.getGuaranteeNotifyUrl() + "/" + channel.getId();
    }

    private String genChannelMemberNotifyUrl(PayChannelDO channel) {
        return payProperties.getMemberNotifyUrl() + "/" + channel.getId();
    }

    private PayChannelDO validateChannelCanSubmit(Long appId, String channelCode) {
        // 校验 App
        appService.validPayApp(appId);
        // 校验支付渠道是否有效
        PayChannelDO channel = channelService.validPayChannel(appId, channelCode);
        PayClient client = channelService.getPayClient(channel.getId());
        if (client == null) {
            log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
            throw exception(CHANNEL_NOT_FOUND);
        }
        return channel;
    }
}